package org.snia.server.dispatcher;

import java.util.Map;
import java.util.Properties;

import javax.naming.InitialContext;
import javax.naming.NamingException;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.snia.cdmi.ErrorCodes;
import org.snia.cdmi.auth.Principal;
import org.snia.cdmi.exception.BadRequestException;
import org.snia.cdmi.exception.ConflictException;
import org.snia.cdmi.exception.ForbiddenException;
import org.snia.cdmi.exception.InternalException;
import org.snia.cdmi.exception.NotFoundException;
import org.snia.cdmi.locator.KetamaNodeLocator;
import org.snia.cdmi.locator.Node;
import org.snia.cdmi.model.AccessControlList;
import org.snia.cdmi.model.Container;
import org.snia.cdmi.model.ContainerProperties;
import org.snia.cdmi.model.ContainerStatus;
import org.snia.cdmi.model.DataObject;
import org.snia.cdmi.model.DataObjectProperties;
import org.snia.cdmi.model.InputDataObject;
import org.snia.cdmi.model.MetaContainer;
import org.snia.cdmi.model.MetaDataObject;
import org.snia.exception.BusinessException;
import org.snia.server.ejb.cache.CacheOperation;
import org.snia.server.ejb.container.ContainerOperation;
import org.snia.server.model.cache.ContainerCache;

/**
 * 只有缓存采用独立的集群，其他服务同服务分发机与执行机同机部署
 * @author Administrator
 *
 */
public class RasDispatcher implements Dispatcher {

	private static Log logger = LogFactory.getLog(RasDispatcher.class);

	private Principal principal;
	
	private InitialContext ctx = null;
	private ContainerOperation remote = null;
	private CacheOperation cache_remote = null;
	
	@Override
	public void createContainer(Container container) {
		// 检查参数
		if (container == null || container.getName() == null) {
			throw new BadRequestException(ErrorCodes.InvalidArgument);
		}
		Properties pros = new Properties();
		pros.setProperty("java.naming.factory.initial",
				"org.jnp.interfaces.NamingContextFactory");
		
		//1.检查集群中是否存在与新建的容器名相同的缓存对象
		//2.缓存不存在，继续检查指定存储位置上的容器元数据文件是否存在
		//3.如果容器的元数据文件不存在，则创建新的元数据文件
		//4.将创建的新容器放入到缓存中
		Node node = KetamaNodeLocator.getCacheLocator().getPrimary(container.getName());
		pros.setProperty("java.naming.provider.url", node.getHost() + ":" + "1099");
		
		ContainerCache cache = null;
		try {
			ctx = new InitialContext(pros);
			cache_remote = (CacheOperation)ctx.lookup("CacheBean/remote");
			cache = (ContainerCache)cache_remote.getCache(container.getName());
		} catch (NamingException e) {
			throw new InternalException(ErrorCodes.InternalError);
		}
		
		if(cache == null){
			node = KetamaNodeLocator.getLocator().getPrimary(container.getName());
			pros.setProperty("java.naming.provider.url", node.getHost() + ":" + "1099");
			try {
				ctx = new InitialContext(pros);
				remote = (ContainerOperation)ctx.lookup("ContainerBean/remote");
			} catch (NamingException e) {
				throw new InternalException(ErrorCodes.InternalError);
			}
			
			if(remote.exist(container.getName())){
				//容器已经存在，抛出异常
				throw new ConflictException(ErrorCodes.ContainerAlreadyExists);
			}
			//创建新容器的元数据信息
			remote.createMetaContainer(container);
			
			//将创建的新容器放入到缓存中
			cache = new ContainerCache(container.getName());
//				cache_service.putCache(cache, node.getHost());
			cache_remote.putCache(container.getName(), cache, 0);
		}else{
			//要创建的容器名在缓存中已存在，则不允许创建
			throw new ConflictException(ErrorCodes.ContainerAlreadyExists);
		}		
	}

	@Override
	public void deleteContainer(String name) {
		//检查参数
		if(StringUtils.isBlank(name)){
			throw new BadRequestException(ErrorCodes.InvalidArgument);
		}
		
		Properties pros = new Properties();
		pros.setProperty("java.naming.factory.initial", "org.jnp.interfaces.NamingContextFactory");
		
		Node cache_node = KetamaNodeLocator.getCacheLocator().getPrimary(name);
		pros.setProperty("java.naming.provider.url", cache_node.getHost() + ":" + "1099");
		
		ContainerCache cache = null;
		try {
			ctx = new InitialContext(pros);
			cache_remote = (CacheOperation)ctx.lookup("CacheBean/remote");
			cache = (ContainerCache)cache_remote.getCache(name);
		} catch (NamingException e) {
			throw new InternalException(ErrorCodes.InternalError);
		}
		
		if(cache != null){
			if(cache.getStatus() != ContainerStatus.Working.getValue()){
				//只有容器状态为正常时，才能进行容器的删除，否则返回409.冲突
				throw new ForbiddenException(ErrorCodes.OperationAborted);
			}
		}
		
		Node node = KetamaNodeLocator.getLocator().getPrimary(name);
		pros.setProperty("java.naming.provider.url", node.getHost() + ":" + "1099");
		MetaContainer metafile = null;
		try {
			ctx = new InitialContext(pros);
			remote = (ContainerOperation)ctx.lookup("ContainerBean/remote");
			metafile = remote.getMetaContainer(name);
		} catch (NamingException e) {
			// TODO Auto-generated catch block
			throw new InternalException(ErrorCodes.InternalError);
		}
		if(metafile != null){
			if(metafile.getStatus() != ContainerStatus.Working.getValue()){
				throw new ForbiddenException(ErrorCodes.OperationAborted);
			}
		}else{
			throw new NotFoundException(ErrorCodes.NoSuchContainer);
		}
		
		//更新容器元数据文件中的容器状态
		metafile.setStatus(ContainerStatus.Releasing.getValue());
		remote.updateMetaContainer(metafile.getUuid(), metafile);
		
		//如果存在缓存，则更新缓存状态。
		if(cache != null){
			cache.setStatus(ContainerStatus.Releasing.getValue());
			cache_remote.updateCache(name, cache);
		}else{
//			TODO 缓存不存在，添加到缓存
		}
		//TODO 容器存在，写入删除容器任务到临时任务表中
		
	}

	@Override
	public void setAccessControlPolicy(String name, AccessControlList acl) {
		//检查参数
		if(StringUtils.isBlank(name)){
			throw new BadRequestException(ErrorCodes.InvalidArgument);
		}
		if(acl == null || acl.getGrants().isEmpty()){
			return;
		}
		Properties pros = new Properties();
		pros.setProperty("java.naming.factory.initial", "org.jnp.interfaces.NamingContextFactory");
		
		Node cache_node = KetamaNodeLocator.getCacheLocator().getPrimary(name);
		pros.setProperty("java.naming.provider.url", cache_node.getHost() + ":" + "1099");
		
		ContainerCache cache = null;
		try {
			ctx = new InitialContext(pros);
			cache_remote = (CacheOperation)ctx.lookup("CacheBean/remote");
			cache = (ContainerCache)cache_remote.getCache(name);
		} catch (NamingException e) {
			throw new InternalException(ErrorCodes.InternalError);
		}
		
		if(cache != null){
			if(cache.getStatus() != ContainerStatus.Working.getValue()){
				//只有容器状态为正常时，才能进行容器的删除，否则返回409.冲突
				throw new ForbiddenException(ErrorCodes.OperationAborted);
			}
		}
		
		Node node = KetamaNodeLocator.getLocator().getPrimary(name);
		pros.setProperty("java.naming.provider.url", node.getHost() + ":" + "1099");
		MetaContainer metafile = null;
		try {
			ctx = new InitialContext(pros);
			remote = (ContainerOperation)ctx.lookup("ContainerBean/remote");
			metafile = remote.getMetaContainer(name);
		} catch (NamingException e) {
			throw new InternalException(ErrorCodes.InternalError);
		}
		if(metafile != null){
			if(metafile.getStatus() != ContainerStatus.Working.getValue()){
				throw new ForbiddenException(ErrorCodes.OperationAborted);
			}
		}else{
			throw new NotFoundException(ErrorCodes.NoSuchContainer);
		}			
		
		//更新容器元数据文件中的容器ACL属性
		metafile.setAccessControlPolicy(acl);
		remote.updateMetaContainer(metafile.getUuid(), metafile);
		
		//如果存在缓存，则更新缓存状态。
		if(cache != null){
			cache.setAccessControlPolicy(acl);
			cache_remote.updateCache(name, cache);
		}else{
//			TODO 缓存不存在，添加到缓存
		}
	}

	@Override
	public Map<String, String> getAccessControlList(String name) {
		//检查参数
		if(StringUtils.isBlank(name)){
			throw new BusinessException(ErrorCodes.InvalidArgument);
		}
		Properties pros = new Properties();
		pros.setProperty("java.naming.factory.initial", "org.jnp.interfaces.NamingContextFactory");

		Node cache_node = KetamaNodeLocator.getCacheLocator().getPrimary(name);
		pros.setProperty("java.naming.provider.url", cache_node.getHost() + ":" + "1099");
		
		ContainerCache cache = null;
		try {
			ctx = new InitialContext(pros);
			cache_remote = (CacheOperation)ctx.lookup("CacheBean/remote");
			cache = (ContainerCache)cache_remote.getCache(name);
		} catch (NamingException e) {
			throw new InternalException(ErrorCodes.InternalError);
		}
		//检查缓存
		if(cache != null){
			Map<String, String> aclMap = cache.getAccessControlList();
			return aclMap;
		}
		//检查元数据
		Node node = KetamaNodeLocator.getLocator().getPrimary(name);
		pros.setProperty("java.naming.provider.url", node.getHost() + ":" + "1099");
		
		try {
			ctx = new InitialContext(pros);
			remote = (ContainerOperation)ctx.lookup("ContainerBean/remote");
			MetaContainer metafile = remote.getMetaContainer(name);
			if(metafile == null){
				throw new NotFoundException(ErrorCodes.NoSuchContainer);
			}
			return metafile.getAccessControlList();
		} catch (NamingException e) {
			throw new InternalException(ErrorCodes.InternalError);
		}			
	}

	@Override
	public ContainerProperties getProperties(String name, boolean withMetadata) {
		//检查参数
		if(StringUtils.isBlank(name)){
			throw new BusinessException(ErrorCodes.InvalidArgument);
		}
		Properties pros = new Properties();
		pros.setProperty("java.naming.factory.initial", "org.jnp.interfaces.NamingContextFactory");
		
		Node node = KetamaNodeLocator.getLocator().getPrimary(name);
		pros.setProperty("java.naming.provider.url", node.getHost() + ":" + "1099");
		
		try {
			ctx = new InitialContext(pros);
			remote = (ContainerOperation)ctx.lookup("ContainerBean/remote");
			return remote.getProperties(name, withMetadata, this.principal);
		} catch (NamingException e) {
			throw new InternalException(ErrorCodes.InternalError);
		}
	}

	@Override
	public void setUserMetadata(String name, Map<String, String> meta) {
		//检查参数
		if(StringUtils.isBlank(name)){
			throw new InternalException(ErrorCodes.InvalidArgument);
		}
		
		if(meta == null || meta.size() == 0){
			return;
		}
		
		Properties pros = new Properties();
		pros.setProperty("java.naming.factory.initial", "org.jnp.interfaces.NamingContextFactory");

		Node node = KetamaNodeLocator.getLocator().getPrimary(name);
		pros.setProperty("java.naming.provider.url", node.getHost() + ":" + "1099");
		
		try {
			ctx = new InitialContext(pros);
			remote = (ContainerOperation)ctx.lookup("ContainerBean/remote");
			remote.setUserMetadata(name, meta, this.principal);
		} catch (NamingException e) {
			throw new InternalException(ErrorCodes.InternalError);
		}
	}

	@Override
	public Map<String, String> getUserMetadata(String name) {
		//检查参数
		if(StringUtils.isBlank(name)){
			throw new BusinessException(ErrorCodes.InvalidArgument);
		}
		Properties pros = new Properties();
		pros.setProperty("java.naming.factory.initial", "org.jnp.interfaces.NamingContextFactory");

		Node node = KetamaNodeLocator.getLocator().getPrimary(name);
		pros.setProperty("java.naming.provider.url", node.getHost() + ":" + "1099");
		
		try {
			ctx = new InitialContext(pros);
			remote = (ContainerOperation)ctx.lookup("ContainerBean/remote");
			return remote.getUserMetadata(name, this.principal);
		} catch (NamingException e) {
			throw new InternalException(ErrorCodes.InternalError);
		}		
	}

	@Override
	public void setAuthorization(Principal principal) {
		this.principal = principal;		
	}

	@Override
	public void createDataObject(InputDataObject object) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void deleteDataObject(String container, String objectUri) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public DataObject getDataObject(String container, String objectUri) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public void setAccessControlPolicy(String container, String objectUri,
			AccessControlList acl) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void setUserMetadata(String container, String objectUri,
			Map<String, String> mapMeta) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public Map<String, String> getUserMetadata(String container,
			String objectUri) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public DataObjectProperties getProperties(String container,
			String objectUri, boolean withMetadata) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public Map<String, String> getAccessControlList(String container,
			String objectUri) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public MetaDataObject copyDataObject(String source, String container,
			String objectUri, boolean replaceFlag) {
				return null;
		// TODO Auto-generated method stub
	}
}
